<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=2">
<meta name="theme-color" content="#222">
<meta name="generator" content="Hexo 5.1.1">
  <link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon-next.png">
  <link rel="icon" type="image/png" sizes="32x32" href="/images/favicon-32x32-next.png">
  <link rel="icon" type="image/png" sizes="16x16" href="/images/favicon-16x16-next.png">
  <link rel="mask-icon" href="/images/logo.svg" color="#222">
  <meta name="google-site-verification" content="T1Dbmn0YmNZwwxNqq98b7FvVCsxbeIChYP6H75TZjdk">
  <meta name="baidu-site-verification" content="code-86L5xW0tJy">

<link rel="stylesheet" href="/css/main.css">



<link rel="stylesheet" href="//cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@5.14.0/css/all.min.css">
  <link rel="stylesheet" href="//cdn.jsdelivr.net/npm/animate.css@3.1.1/animate.min.css">

<script class="hexo-configurations">
    var NexT = window.NexT || {};
    var CONFIG = {"hostname":"www.whatsblockchain.com","root":"/","scheme":"Gemini","version":"8.0.0","exturl":false,"sidebar":{"position":"left","display":"post","padding":18,"offset":12},"copycode":false,"bookmark":{"enable":false,"color":"#222","save":"auto"},"fancybox":false,"mediumzoom":false,"lazyload":false,"pangu":false,"comments":{"style":"tabs","active":null,"storage":true,"lazyload":false,"nav":null},"motion":{"enable":true,"async":false,"transition":{"post_block":"fadeIn","post_header":"fadeInDown","post_body":"fadeInDown","coll_header":"fadeInLeft","sidebar":"fadeInUp"}},"prism":false,"i18n":{"placeholder":"搜索...","empty":"没有找到任何搜索结果：${query}","hits_time":"找到 ${hits} 个搜索结果（用时 ${time} 毫秒）","hits":"找到 ${hits} 个搜索结果"}};
  </script>

  <meta name="description" content="关于零知识证明是什么，也许你不一定很了解，但说到应用零知识证明技术的区块链产品，你也许并不陌生。zcash就是使用零知识证明技术的隐私币，以太坊上的混币合约也是零知识证明技术的一个应用，还有在今年比较热门的链下扩容技术zkRollup也是零知识证明技术的一个应用。这时你也许会很好奇零知识证明究竟是一个什么样的技术，为什么既可以用在隐私方面，也可以用于扩容。在接下来一个系列的文章中将为你一一介绍，从">
<meta property="og:type" content="article">
<meta property="og:title" content="零知识证明介绍 ">
<meta property="og:url" content="https://www.whatsblockchain.com/posts/58cf1c1b.html">
<meta property="og:site_name" content="区块链大杂烩">
<meta property="og:description" content="关于零知识证明是什么，也许你不一定很了解，但说到应用零知识证明技术的区块链产品，你也许并不陌生。zcash就是使用零知识证明技术的隐私币，以太坊上的混币合约也是零知识证明技术的一个应用，还有在今年比较热门的链下扩容技术zkRollup也是零知识证明技术的一个应用。这时你也许会很好奇零知识证明究竟是一个什么样的技术，为什么既可以用在隐私方面，也可以用于扩容。在接下来一个系列的文章中将为你一一介绍，从">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="https://www.whatsblockchain.com/assets/2020-06-30/1.png">
<meta property="og:image" content="https://www.whatsblockchain.com/assets/2020-06-30/2.png">
<meta property="og:image" content="https://www.whatsblockchain.com/assets/2020-06-30/3.png">
<meta property="og:image" content="https://www.whatsblockchain.com/assets/2020-06-30/4.png">
<meta property="og:image" content="https://www.whatsblockchain.com/assets/2020-06-30/5.png">
<meta property="og:image" content="https://www.whatsblockchain.com/assets/2020-06-30/6.png">
<meta property="og:image" content="https://www.whatsblockchain.com/assets/2020-06-30/7.png">
<meta property="og:image" content="https://www.whatsblockchain.com/assets/2020-06-30/8.png">
<meta property="og:image" content="https://www.whatsblockchain.com/assets/2020-06-30/9.png">
<meta property="og:image" content="https://www.whatsblockchain.com/assets/2020-06-30/10.png">
<meta property="og:image" content="https://www.whatsblockchain.com/assets/2020-06-30/11.png">
<meta property="og:image" content="https://www.whatsblockchain.com/assets/2020-06-30/12.png">
<meta property="article:published_time" content="2020-06-29T16:00:00.000Z">
<meta property="article:modified_time" content="2020-09-16T06:57:25.023Z">
<meta property="article:author" content="吴寿鹤">
<meta property="article:tag" content="以太坊">
<meta property="article:tag" content="零知识证明">
<meta property="article:tag" content="区块链">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="https://www.whatsblockchain.com/assets/2020-06-30/1.png">


<link rel="canonical" href="https://www.whatsblockchain.com/posts/58cf1c1b.html">


<script class="page-configurations">
  // https://hexo.io/docs/variables.html
  CONFIG.page = {
    sidebar: "",
    isHome : false,
    isPost : true,
    lang   : 'zh-CN'
  };
</script>

  <title>零知识证明介绍  | 区块链大杂烩</title>
  
    <script async src="https://www.googletagmanager.com/gtag/js?id=UA-145440251-1"></script>
    <script>
      if (CONFIG.hostname === location.hostname) {
        window.dataLayer = window.dataLayer || [];
        function gtag(){dataLayer.push(arguments);}
        gtag('js', new Date());
        gtag('config', 'UA-145440251-1');
      }
    </script>


  <script>
    var _hmt = _hmt || [];
    (function() {
      var hm = document.createElement("script");
      hm.src = "https://hm.baidu.com/hm.js?9af0452214522472f44968f5a652e2f0";
      var s = document.getElementsByTagName("script")[0];
      s.parentNode.insertBefore(hm, s);
    })();
  </script>




  <noscript>
  <style>
  body { margin-top: 2rem; }

  .use-motion .menu-item,
  .use-motion .sidebar,
  .use-motion .post-block,
  .use-motion .pagination,
  .use-motion .comments,
  .use-motion .post-header,
  .use-motion .post-body,
  .use-motion .collection-header {
    visibility: visible;
  }

  .use-motion .header,
  .use-motion .site-brand-container .toggle,
  .use-motion .footer { opacity: initial; }

  .use-motion .site-title,
  .use-motion .site-subtitle,
  .use-motion .custom-logo-image {
    opacity: initial;
    top: initial;
  }

  .use-motion .logo-line {
    transform: scaleX(1);
  }

  .search-pop-overlay, .sidebar-nav { display: none; }
  .sidebar-panel { display: block; }
  </style>
</noscript>

<!-- hexo injector head_end start -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.12.0/dist/katex.min.css">

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/hexo-math@4.0.0/dist/style.css">
<!-- hexo injector head_end end --></head>

<body itemscope itemtype="http://schema.org/WebPage" class="use-motion">
  <div class="headband"></div>

  <main class="main">
    <header class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner"><div class="site-brand-container">
  <div class="site-nav-toggle">
    <div class="toggle" aria-label="切换导航栏">
        <span class="toggle-line"></span>
        <span class="toggle-line"></span>
        <span class="toggle-line"></span>
    </div>
  </div>

  <div class="site-meta">

    <a href="/" class="brand" rel="start">
      <i class="logo-line"></i>
      <h1 class="site-title">区块链大杂烩</h1>
      <i class="logo-line"></i>
    </a>
      <p class="site-subtitle" itemprop="description">你想要的这里都有</p>
  </div>

  <div class="site-nav-right">
    <div class="toggle popup-trigger">
    </div>
  </div>
</div>



<nav class="site-nav">
  <ul class="main-menu menu">
        <li class="menu-item menu-item-home">

    <a href="/" rel="section"><i class="fa fa-home fa-fw"></i>首页</a>

  </li>
        <li class="menu-item menu-item-about">

    <a href="/about/" rel="section"><i class="fa fa-user fa-fw"></i>关于</a>

  </li>
        <li class="menu-item menu-item-tags">

    <a href="/tags/" rel="section"><i class="fa fa-tags fa-fw"></i>标签</a>

  </li>
        <li class="menu-item menu-item-categories">

    <a href="/categories/" rel="section"><i class="fa fa-th fa-fw"></i>分类</a>

  </li>
        <li class="menu-item menu-item-archives">

    <a href="/archives/" rel="section"><i class="fa fa-archive fa-fw"></i>归档</a>

  </li>
  </ul>
</nav>




</div>
        
  
  <div class="toggle sidebar-toggle">
    <span class="toggle-line"></span>
    <span class="toggle-line"></span>
    <span class="toggle-line"></span>
  </div>

  <aside class="sidebar">

    <div class="sidebar-inner sidebar-nav-active sidebar-toc-active">
      <ul class="sidebar-nav">
        <li class="sidebar-nav-toc">
          文章目录
        </li>
        <li class="sidebar-nav-overview">
          站点概览
        </li>
      </ul>

      <!--noindex-->
      <section class="post-toc-wrap sidebar-panel">
          <div class="post-toc animated"><ol class="nav"><li class="nav-item nav-level-2"><a class="nav-link" href="#%E4%BB%80%E4%B9%88%E6%98%AF%E9%9B%B6%E7%9F%A5%E8%AF%86%E8%AF%81%E6%98%8E"><span class="nav-number">1.</span> <span class="nav-text">什么是零知识证明</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E4%BA%A4%E4%BA%92%E5%BC%8F%E9%9B%B6%E7%9F%A5%E8%AF%86%E8%AF%81%E6%98%8E%E2%80%94-%E8%89%B2%E7%9B%B2%E6%B8%B8%E6%88%8F"><span class="nav-number">1.1.</span> <span class="nav-text">交互式零知识证明—-色盲游戏</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E9%9D%9E%E4%BA%A4%E4%BA%92%E9%9B%B6%E7%9F%A5%E8%AF%86%E8%AF%81%E6%98%8E%E2%80%94-%E6%95%B0%E7%8B%AC%E6%B8%B8%E6%88%8F"><span class="nav-number">1.2.</span> <span class="nav-text">非交互零知识证明—-数独游戏</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#%E6%95%B0%E7%8B%AC%E6%B8%B8%E6%88%8F%E9%A2%98%E7%9B%AE"><span class="nav-number">1.2.1.</span> <span class="nav-text">数独游戏题目</span></a></li></ol></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E9%9B%B6%E7%9F%A5%E8%AF%86%E8%AF%81%E6%98%8E%E5%BA%94%E7%94%A8%E5%9C%BA%E6%99%AF"><span class="nav-number">2.</span> <span class="nav-text">零知识证明应用场景</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E9%9A%90%E7%A7%81"><span class="nav-number">2.1.</span> <span class="nav-text">隐私</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E6%89%A9%E5%AE%B9"><span class="nav-number">2.2.</span> <span class="nav-text">扩容</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#%E9%93%BE%E4%B8%8B%E6%89%A9%E5%AE%B9"><span class="nav-number">2.2.1.</span> <span class="nav-text">链下扩容</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#%E9%93%BE%E4%B8%8A%E5%8E%8B%E7%BC%A9"><span class="nav-number">2.2.2.</span> <span class="nav-text">链上压缩</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#%E9%80%92%E5%BD%92%E9%9B%B6%E7%9F%A5%E8%AF%86%E8%AF%81%E6%98%8E"><span class="nav-number">2.2.3.</span> <span class="nav-text">递归零知识证明</span></a></li></ol></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E9%9B%B6%E7%9F%A5%E8%AF%86%E8%AF%81%E6%98%8E%E5%8D%8F%E8%AE%AE"><span class="nav-number">3.</span> <span class="nav-text">零知识证明协议</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E9%9B%B6%E7%9F%A5%E8%AF%86%E8%AF%81%E6%98%8E%E5%8D%8F%E8%AE%AE%E7%89%B9%E6%80%A7%E5%AF%B9%E6%AF%94"><span class="nav-number">3.1.</span> <span class="nav-text">零知识证明协议特性对比</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%8F%91%E5%B1%95%E5%8E%86%E5%8F%B2"><span class="nav-number">4.</span> <span class="nav-text">发展历史</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E9%9B%B6%E7%9F%A5%E8%AF%86%E8%AF%81%E6%98%8E%E5%BC%80%E5%8F%91%E5%B7%A5%E5%85%B7"><span class="nav-number">5.</span> <span class="nav-text">零知识证明开发工具</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#libsnark"><span class="nav-number">5.1.</span> <span class="nav-text">libsnark</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#bellman"><span class="nav-number">5.2.</span> <span class="nav-text">bellman</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#ZoKrates"><span class="nav-number">5.3.</span> <span class="nav-text">ZoKrates</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E9%9B%B6%E7%9F%A5%E8%AF%86%E8%AF%81%E6%98%8E%E7%9A%84%E4%BC%98%E7%BC%BA%E7%82%B9"><span class="nav-number">6.</span> <span class="nav-text">零知识证明的优缺点</span></a></li></ol></div>
      </section>
      <!--/noindex-->

      <section class="site-overview-wrap sidebar-panel">
        <div class="site-author animated" itemprop="author" itemscope itemtype="http://schema.org/Person">
  <p class="site-author-name" itemprop="name">吴寿鹤</p>
  <div class="site-description" itemprop="description">代码之美，在于架构，架构之美，在于抽象</div>
</div>
<div class="site-state-wrap animated">
  <nav class="site-state">
      <div class="site-state-item site-state-posts">
          <a href="/archives/">
        
          <span class="site-state-item-count">21</span>
          <span class="site-state-item-name">日志</span>
        </a>
      </div>
      <div class="site-state-item site-state-categories">
            <a href="/categories/">
          
        <span class="site-state-item-count">7</span>
        <span class="site-state-item-name">分类</span></a>
      </div>
      <div class="site-state-item site-state-tags">
            <a href="/tags/">
          
        <span class="site-state-item-count">11</span>
        <span class="site-state-item-name">标签</span></a>
      </div>
  </nav>
</div>



      </section>
    </div>
  </aside>
  <div class="sidebar-dimmer"></div>


    </header>

    
  <div class="back-to-top">
    <i class="fa fa-arrow-up"></i>
    <span>0%</span>
  </div>

<noscript>
  <div class="noscript-warning">Theme NexT works best with JavaScript enabled</div>
</noscript>


    <div class="main-inner post posts-expand">
      

      

    
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="https://www.whatsblockchain.com/posts/58cf1c1b.html">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.gif">
      <meta itemprop="name" content="吴寿鹤">
      <meta itemprop="description" content="代码之美，在于架构，架构之美，在于抽象">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="区块链大杂烩">
    </span>

    
    
      <header class="post-header">
        <h1 class="post-title" itemprop="name headline">
          零知识证明介绍 
        </h1>

        <div class="post-meta-container">
          <div class="post-meta">
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-calendar"></i>
      </span>
      <span class="post-meta-item-text">发表于</span>

      <time title="创建时间：2020-06-30 00:00:00" itemprop="dateCreated datePublished" datetime="2020-06-30T00:00:00+08:00">2020-06-30</time>
    </span>
      <span class="post-meta-item">
        <span class="post-meta-item-icon">
          <i class="far fa-calendar-check"></i>
        </span>
        <span class="post-meta-item-text">更新于</span>
        <time title="修改时间：2020-09-16 14:57:25" itemprop="dateModified" datetime="2020-09-16T14:57:25+08:00">2020-09-16</time>
      </span>
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-folder"></i>
      </span>
      <span class="post-meta-item-text">分类于</span>
        <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
          <a href="/categories/%E9%9B%B6%E7%9F%A5%E8%AF%86%E8%AF%81%E6%98%8E/" itemprop="url" rel="index"><span itemprop="name">零知识证明</span></a>
        </span>
    </span>

  
    <span class="post-meta-item" title="阅读次数" id="busuanzi_container_page_pv" style="display: none;">
      <span class="post-meta-item-icon">
        <i class="far fa-eye"></i>
      </span>
      <span class="post-meta-item-text">阅读次数：</span>
      <span id="busuanzi_value_page_pv"></span>
    </span>
      </div>
      <div class="post-meta">
    <span class="post-meta-item" title="本文字数">
      <span class="post-meta-item-icon">
        <i class="far fa-file-word"></i>
      </span>
      <span class="post-meta-item-text">本文字数：</span>
      <span>6.5k</span>
    </span>
    <span class="post-meta-item" title="阅读时长">
      <span class="post-meta-item-icon">
        <i class="far fa-clock"></i>
      </span>
      <span class="post-meta-item-text">阅读时长 &asymp;</span>
      <span>6 分钟</span>
    </span>
</div>

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">
        <p>关于零知识证明是什么，也许你不一定很了解，但说到应用零知识证明技术的区块链产品，你也许并不陌生。zcash就是使用零知识证明技术的隐私币，以太坊上的混币合约也是零知识证明技术的一个应用，还有在今年比较热门的链下扩容技术<code>zkRollup</code>也是零知识证明技术的一个应用。这时你也许会很好奇零知识证明究竟是一个什么样的技术，为什么既可以用在隐私方面，也可以用于扩容。在接下来一个系列的文章中将为你一一介绍，从零知识证明的概念一直到零知识证明背后的密码学实现。</p>
<a id="more"></a>
<h2 id="什么是零知识证明"><a href="#什么是零知识证明" class="headerlink" title="什么是零知识证明"></a>什么是零知识证明</h2><p>零知识证明的定义为：证明者（<code>prover</code>）能够在不向验证者（<code>verifier</code>）提供任何有用的信息的情况下，使验证者（<code>verifier</code>）相信某个论断是正确的。</p>
<p>为了理解上面这段话的含义，接下来给出一个有关零知识证明的非常经典的例子：</p>
<h3 id="交互式零知识证明—-色盲游戏"><a href="#交互式零知识证明—-色盲游戏" class="headerlink" title="交互式零知识证明—-色盲游戏"></a>交互式零知识证明—-色盲游戏</h3><p><code>Alice</code>是色盲，<code>Bob</code>不是色盲，在<code>Bob</code>手上有两个大小，形状完全一样的球，但这两个球的颜色不一样，一个球是蓝色的，另一个球是红色的，由于<code>Alice</code>是色盲，所以<code>Alice</code>无法分辨这两个球是否是一样的，<code>Bob</code>需要向<code>Alice</code>证明这两个球是不一样的。在这里，<code>Alice</code>被称为验证者，他需要验证<code>Bob</code>的陈述正确与否，<code>Bob</code>被称为证明者，他需要证明自己的陈述（存在两个颜色不一样的球），<code>Bob</code>需要在<code>Alice</code>不能获得两个球的颜色的情况下，向<code>Alice</code>证明这两个球的颜色是不一样的这个事实，这与零知识证明的定义是相符合的。</p>
<p><code>Alice</code>当<code>Bob</code>的面拿起两个球，左手拿蓝球，右手拿红球，然后将双手放到背后，这样<code>Bob</code>就看不到<code>Alice</code>手上的球了，<code>Alice</code>在背后随机交换左右手上的球，交换完成后<code>Alice</code>将手伸出，并询问<code>Bob</code>两个球是否交换过位置，如果<code>Bob</code>能看到球上的颜色，那么每次<code>Alice</code>换过球的位置后，<code>Bob</code>都能正确回答出<code>Alice</code>的问题。</p>
<p><img src="/assets/2020-06-30/1.png" alt="img"></p>
<p>第一次，<code>Alice</code>偷偷交换了手中球的位置，然后<code>Alice</code>问<code>Bob</code>是否交换了球的位置，如果<code>Bob</code>回答Yes，那么<code>Alice</code>有50%的概率相信<code>Bob</code>是可以区分这两个球的颜色，因为<code>Bob</code>有1/2的概率蒙对，所以<code>Alice</code>可以在进行一次测试。如果<code>Bob</code>回答No，那么<code>Alice</code>可以肯定<code>Bob</code>不能区分两个球的颜色。</p>
<p><img src="/assets/2020-06-30/2.png" alt="img"></p>
<p>第二次，<code>Alice</code>没有交换手中球的位置，然后<code>Alice</code>问<code>Bob</code>是否交换了球的位置。如果<code>Bob</code>回答No，那么<code>Alice</code>有75%的概率相信<code>Bob</code>是可以区分两个球的颜色。</p>
<p><img src="/assets/2020-06-30/3.png" alt="img"></p>
<p>这是上述情况的概率树：</p>
<p><img src="/assets/2020-06-30/4.png" alt="概率树"></p>
<p>第一次迭代后，<code>Alice</code>可以说<code>Bob</code>陈述的断言为真的概率为50％。如果<code>Bob</code>第二次回答正确，那么<code>Alice</code>可以说<code>Bob</code>陈述为真的概率达75％。在第三次迭代后，它将是87.5％。如果连续<code>n</code>次<code>Bob</code>都通过了检查，则<code>Alice</code>有<code>1-(1/2)^n</code> 的概率可以认为 <code>Bob</code> 说的是真的，这两个球的确是有红蓝两种颜色。</p>
<p>零知识证明是一种基于概率的验证方式，验证者（<code>verifier</code>）基于一定的随机性向证明者（<code>prover</code>)提出问题，如果证明者都能给出正确回答，则说明证明者大概率拥有他所声称的“知识”。零知识证明并不是数学意义上的证明，因为它存在小概率的误差，欺骗的证明者有可能通过虚假的陈诉骗过验证者。换句话说，零知识证明是概率证明而不是确定性证明，但是也存在技术能将误差降低到可以忽略的值。</p>
<p>根据零知识证明的定义可以得知零知识证明具有以下三个重要的性质：</p>
<ol>
<li>完备性（<code>Completeness</code>）：只要证明者拥有相应的知识，那么就能通过验证者的验证，即证明者有足够大的概率使验证者确信。；</li>
<li>可靠性（<code>Soundness</code>）：如果证明者没有相应的知识，则无法通过验证者的验证，即证明者欺骗验证者的概率可以忽略。</li>
<li>零知识性（<code>Zero-Knowledge</code>）：证明者在交互过程中仅向验证者透露是否拥有相应知识的陈述，不会泄露任何关于知识的额外信息。</li>
</ol>
<p>在此示例中，如果<code>Bob</code>的拥有分别球颜色的知识，则<code>Bob</code>每次都会正确回答。这称为完备性。如果<code>Bob</code>不具备分别球颜色的相关知识，则<code>Bob</code>无法分辨<code>Alice</code>是否调换了球。这称为可靠性。在此协议中，<code>Alice</code>无法看到球的颜色。这称为零知识性。</p>
<h3 id="非交互零知识证明—-数独游戏"><a href="#非交互零知识证明—-数独游戏" class="headerlink" title="非交互零知识证明—-数独游戏"></a>非交互零知识证明—-数独游戏</h3><p>交互式零知识证明协议依赖于验证者的随机尝试，需要证明者和验证者进行多次交互才能完成。非交互式零知识证明（<code>Non-Interactive Zero-Knowledge, NIZK</code>）将交互次数减少到一次，可实现离线证明和公开验证。在区块链等零知识证明应用场景中，非交互的性质是必须的，因为在区块链系统中，不能假设双方一直在线进行交互，在区块链网络上，证明者只要向全网广播一条证明交易，网络上的矿工在将这条交易打包到区块中的时候就帮验证者完成了零知识证明的校验。</p>
<h4 id="数独游戏题目"><a href="#数独游戏题目" class="headerlink" title="数独游戏题目"></a>数独游戏题目</h4><p>数独是源自18世纪瑞士的一种数学游戏，是一种运用纸、笔进行演算的逻辑游戏。玩家需要根据9×9盘面上的已知数字，推理出所有剩余空格的数字，并满足每一行、每一列、每一个粗线宫（3*3）内的数字均含1-9，不重复。</p>
<p><img src="/assets/2020-06-30/5.png" alt="img"></p>
<p><code>Alice</code>为了向<code>Bob</code>证明他已经解决了一个数独难题，为此<code>Alice</code>创建了一个防篡改的机器。<code>Alice</code>将生成好的数独答案放入到机器中，机器可以向<code>Bob</code>发送证明。<code>Alice</code>的机器遵循以下公开可验证的协议：</p>
<p>首先，<code>Alice</code>在机器中放入尚未被解决的原始数独题目，数独中的谜题卡片三张正面朝上，例如，单元格C3具有3张正面朝上的9号卡片。</p>
<p><img src="/assets/2020-06-30/6.png" alt="img"></p>
<p>接下来，<code>Alice</code>上机器将他的答案正面朝下放置在相应的单元格上，同样也是每个单元格放三张。</p>
<p><img src="/assets/2020-06-30/7.png" alt="img"></p>
<p>最后<code>Bob</code>向机器获取证明，机器返回给<code>Bob</code>27个袋子：</p>
<ul>
<li>机器将数独中每一行9张卡片取出，并分别混淆后放入一个袋子中，一共有9行，所以9个袋子</li>
<li>机器将数独中每一列9张卡片取出，并分别混淆后放入一个袋子中，一共有9列，所以9个袋子</li>
<li>机器将数独中每个粗线宫（3*3）内卡片取出，并分别混淆后放入一个袋子中，一共有9个，所以9个袋子</li>
</ul>
<p><img src="/assets/2020-06-30/8.png" alt="img"></p>
<p><code>Bob</code>分别对这27个袋子进行检查，如果每个袋子中的卡片都包含数字1到9，而且没有任何数字丢失或重复，那么<code>Bob</code>可以确认<code>Alice</code>的确解开了数独，并且<code>Bob</code>并没有从机器返回的证明中获取任何关于数独解的知识，因为机器返回给<code>Bob</code>袋子中的数据是被随机打乱的。</p>
<p><img src="/assets/2020-06-30/9.png" alt="img"></p>
<h2 id="零知识证明应用场景"><a href="#零知识证明应用场景" class="headerlink" title="零知识证明应用场景"></a>零知识证明应用场景</h2><p>零知识证明的定义为：证明者（<code>prover</code>）能够在不向验证者（<code>verifier</code>）提供任何有用的信息的情况下，使验证者（<code>verifier</code>）相信某个论断是正确的。</p>
<p>从零知识证明定义中可以提取到两个关键词：“不泄露信息”，“证明论断有效”，基于这两个特点扩展出零知识证明在区块链上的两大应用场景：</p>
<ul>
<li>隐私：在隐私场景中，我们可以借助零知识证明的“不泄露信息”特性，在不泄漏交易的细节（接收方，发送方，交易余额）的情况下证明区块链上的资产转移是有效的。</li>
<li>扩容：在扩容场景中，我们不太需要关注零知识证明技术的“不泄露信息”这个特性，我们的关注重点是它的“证明论断有效”这个特性，由于链上资源是有限的，所以我们需要把大量的计算迁移到链下进行，因此需要有一种技术能够证明这些在链下发生的动作是可信的，零知识证明正好可以帮助我们做链下可信计算的背书。</li>
</ul>
<h3 id="隐私"><a href="#隐私" class="headerlink" title="隐私"></a>隐私</h3><p>在目前主流的公链，如比特币、以太坊上，从创世块开始，每个账号之间的交易信息都是公开记录在区块链上，这样做的好处是可以有效解决加密货币双花的问题，矿工可以溯源，校验每笔交易的余额是否足够。坏处是一旦某个账号的身份暴露了，那么第三方就可以追踪到这个账号的以往所有历史交易，甚至还可以反推出这个账号可能控制的其他账号，从这一点来说是相当缺乏隐私的。</p>
<p>要让交易在不泄漏交易相关细节的情况下可以被验证，这正是零知识证明解决的问题。要了解零知识证明是如何解决链上交易隐私的问题，可以参考以下两篇文章。</p>
<p>混币的原理参考：</p>
<ul>
<li><a target="_blank" rel="noopener" href="https://mp.weixin.qq.com/s/_IrI8SJLo1Ht51nJfI4V_Q">10分钟开发混币原理篇</a></li>
<li><a target="_blank" rel="noopener" href="https://mp.weixin.qq.com/s/8OkwqNXIkUz2PBURoghRJQ">10分钟开发混币实操篇</a></li>
</ul>
<h3 id="扩容"><a href="#扩容" class="headerlink" title="扩容"></a>扩容</h3><p>17年出现了一款非常火爆的Dapp应用叫加密猫，加密猫曾造成以太坊主网大规模的拥堵，造成拥堵的原因是以太坊当时的TPS只有15，这意味着以太坊每秒只能处理15笔交易，如此低的TPS严重限制了区块链应用的大规模落地，所以有人开始研究区块链扩容的问题，目的就是为了提高链上的TPS。但区块链扩容受到<code>Vitalik</code>提出的不可能三角的限制，不可能三角是指区块链系统设计无法同时兼顾可扩展性，去中心化和安全性，三者只能取其二。这是一个很让人失望的结论，但我们必须知道，一切事物都有自己的边界，公链不应该做所有的事情，公链应该做它该做的事情：“公链是以最高效率达成共识的工具，能够以最低成本来构建信任”。作为共识的工具，信任的引擎，公链不应该为了可扩展性放弃去中心化与安全性。那么公链的TPS这么低，该怎么使用呢？我们是否可以将大量的工作放到链下去解决，仅仅将最重要的数据提交到区块链主链上，让所有节点都能够验证这些链下的工作都是准确可靠的呢？社会的发展带来的是更精细化的分工，区块链的技术发展也是如此，在底层区块链（Layer1）上构建一个扩展层（Layer2)，Layer1来保证安全和去中心化，绝对可靠、可信；它能做到全球共识，并作为“加密法院”，通过智能合约设计的规则进行仲裁，以经济激励的形式将信任传递到Layer2 上，而Layer2追求极致的性能，它只能做到局部共识，但是能够满足各类商业场景的需求。</p>
<h4 id="链下扩容"><a href="#链下扩容" class="headerlink" title="链下扩容"></a>链下扩容</h4><p>ZK-Rollup就是基于零知识证明的二层扩容方案， ZK-Rollup方案起源于18年下半年，由<code>Barry Whitehat</code>和<code>Vitalik</code>先后提出。关于<code>zkRollup</code>介绍参考下面这篇文章：</p>
<p><a target="_blank" rel="noopener" href="https://mp.weixin.qq.com/s/Si6JorP4WWnMm-c3fIX1mA">zkRollup介绍 原理篇</a></p>
<h4 id="链上压缩"><a href="#链上压缩" class="headerlink" title="链上压缩"></a>链上压缩</h4><p>运行过以太坊全节点的人都会有这样的感受：“同步以太坊全节点的过程太痛苦了”，往往同步以太坊全节点需要花费几天的时间，目前以太坊全节点已经达到<code>399,45Gb</code>。全节点对存储资源要求这样高，以至于很多个人电脑的硬盘空间和带宽都达不到运行全节点的要求，所以全节点变成了只有少部分实体能够运行的，区块链逐渐从去中心化变成了中心化运行。<br><a target="_blank" rel="noopener" href="https://etherscan.io/chartsync/chaindefault">etherscan以太坊全节点统计网址</a></p>
<p><img src="/assets/2020-06-30/10.png" alt="img"></p>
<p>全节点同步时间长的原因如下：</p>
<ul>
<li>全节点数据量太大，下载几百GB的数据需要很长时间。</li>
<li>验证同步到本地的区块是否正确需要花费时间，因为有恶意节点会发送无效的区块。</li>
</ul>
<p>在同步全节点过程中，为了验证链的正确性，需要从创世区块开始依次重放每个交易，然后验证计算出的账户状态是否与同步的状态相同。这不仅耗时，同时也是一种资源浪费，因为在你之前已有无数节点重复了相同的计算工作。我们之所以要重放每个区块的原因是：“我们目前判断一个计算是否正确执行的方法只有重新做一次这个计算，然后比较两者的结果是否相等”。有了零知识证明我们就不需要重复计算区块每个交易了，因为零知识证明可以帮助我们校验每个区块中的交易是否被正确执行。</p>
<p>目前有一个项目<code>Coda</code>，它采用零知识证明的方式将区块大小控制在<code>22kB</code>，且<code>Coda</code>的区块大小是固定的，不会随着时间增长而变大（递归零知识证明），从安全性角度来说，<code>Coda</code>的安全性不会低于传统区块链。</p>
<p><img src="/assets/2020-06-30/11.png" alt="img"></p>
<p>零知识证明压缩链上数据的好处：</p>
<ul>
<li>不需要做重复的计算验证区块状态，减少计算资源浪费</li>
<li>区块链大小只有<code>22k</code>方便存储，同步，验证</li>
<li>由于运行<code>Coda</code>全节点的需要的资源少，所以区块链网络将有更多活跃节点，提升了去中心化程度</li>
</ul>
<h4 id="递归零知识证明"><a href="#递归零知识证明" class="headerlink" title="递归零知识证明"></a>递归零知识证明</h4><p>递归零知识证明生成：使用前一个状态的<code>proof</code>以及当前交易作为输入，接下来验证前一个状态的<code>proof</code>以及当前交易是否有效，如果全部验证通过，程序会输出一个新的状态及一个<code>proof</code>，过程如下图所示：</p>
<p><img src="/assets/2020-06-30/12.png" alt="img"></p>
<p>递归零知识证明验证：只要验证前一个状态的<code>proof</code>就可以验证整个链的状态，比如：当验证<code>proof #5</code>状态是正确的，相当于递归验证了<code>proof #4</code>，<code>proof #3</code>。</p>
<h2 id="零知识证明协议"><a href="#零知识证明协议" class="headerlink" title="零知识证明协议"></a>零知识证明协议</h2><div class="table-container">
<table>
<thead>
<tr>
<th></th>
<th>zk-Snark</th>
<th>Zk-Stark</th>
<th>Bbulletproofs</th>
</tr>
</thead>
<tbody>
<tr>
<td>介绍</td>
<td>简明非交互零知识证明</td>
<td>简洁透明的零知识证明</td>
<td></td>
</tr>
<tr>
<td>关键特性</td>
<td>生成的证明小<br />验证速度快</td>
<td>没有可信设置过程<br />生成证明时间快<br />抗量子攻击</td>
<td>没有可信设置过程</td>
</tr>
<tr>
<td>项目应用</td>
<td>zcash<br />coda</td>
<td>StarkDEX</td>
<td>Monero</td>
</tr>
</tbody>
</table>
</div>
<h3 id="零知识证明协议特性对比"><a href="#零知识证明协议特性对比" class="headerlink" title="零知识证明协议特性对比"></a>零知识证明协议特性对比</h3><ul>
<li><code>Trusted Set-up（可信设置）</code>：是否需要可信设置</li>
<li><code>Speed（Verifier + prover）</code>：证明者生成证明和验证者验证证明所花费的时间总和。</li>
<li><code>Proof Size</code>：生成零知识证明的大小</li>
<li><code>Quantum Resistant（抗量子）</code>：是否抗量子攻击，在未来量子计算可能会对现有的加密算法带来威胁，</li>
</ul>
<div class="table-container">
<table>
<thead>
<tr>
<th></th>
<th>Trusted Set-Up</th>
<th>Speed<br />(Verifier + Prover)</th>
<th>Proof Size</th>
<th>Quantun<br />Resistant</th>
</tr>
</thead>
<tbody>
<tr>
<td>Zk-Snark</td>
<td>Yes</td>
<td>Middle</td>
<td>Smallest</td>
<td>No</td>
</tr>
<tr>
<td>Zk-Stark</td>
<td>No</td>
<td>Fastest</td>
<td>Biggest</td>
<td>Yes</td>
</tr>
<tr>
<td>Bulletproofs</td>
<td>No</td>
<td>Slowest</td>
<td>Middle</td>
<td>No</td>
</tr>
</tbody>
</table>
</div>
<h2 id="发展历史"><a href="#发展历史" class="headerlink" title="发展历史"></a>发展历史</h2><ul>
<li>1985 年，零知识证明<code>Zero-Knowledge Proof</code> - 由 <code>S.Goldwasser</code>、 <code>S.Micali</code> 及 <code>C.Rackoff</code> 首次提出。</li>
<li>2010年，<code>Groth</code>实现了首个基于椭圆曲线双线性映射全能的，常数大小的非交互式零知识证明协议。后来这个协议经过不断优化，最终成为区块链著名的零知识证明协议<code>SNARKs</code>。</li>
<li>2013年，<code>Pinocchio</code>协议实现了分钟级别证明，毫秒级别验证，证明大小不到<code>300</code>字节，将零知识证明从理论带到了应用。后来<code>Zcash</code>使用的<code>SNARKs</code>正是基于<code>Pinocchio</code>的改进版。</li>
<li>2014 年，名为<code>Zerocash</code>的加密货币则使用了一种特殊的零知识证明工具<code>zk-SNARKs</code> （ <code>Zero-Knowledge Succinct Non-interactive Arguments of Knowledge</code> ) 实现了对交易金额、交易双方的完全隐藏，更注重于隐私，以及对交易透明的可控性。</li>
<li>2017 年， <code>Zerocash</code> 团队提出将 <code>zk-SNARKs</code> 与智能合约相互结合的方案，使交易能在众目睽睽下隐身，打造保护隐私的智能合约。</li>
</ul>
<h2 id="零知识证明开发工具"><a href="#零知识证明开发工具" class="headerlink" title="零知识证明开发工具"></a>零知识证明开发工具</h2><p>目前，为了解决零知识证明技术的广泛应用需求，产生了多个用于实现<code>zk-SNARK</code> 零知识证明协议工程化的开源算法库，包括 <code>libsnark</code>、<code>bellman</code>、<code>ZoKrates</code> 等等。</p>
<h3 id="libsnark"><a href="#libsnark" class="headerlink" title="libsnark"></a>libsnark</h3><p><code>libsnark</code>是一个基于<code>C++</code>语言的<code>zk-SNARK</code>工程开发算法库，由<code>SCIPR Lab</code>开发和维护，开发者中包含参与多篇<code>zk-SNARK</code>学术论文的共同作者。<code>libsnark</code>实现了近年来多个主流的<code>zk-SNARK</code>论文方案，其中最为常用的包括<code>BCTV14a</code>和<code>Groth16</code>方案。</p>
<p><code>libsnark</code>实现了<code>zk-SNARK</code>算法的黑盒化，提供高度抽象的编程接口，使开发者无需掌握算法细节即可直接进行工程开发。此外，<code>libsnark</code>还提供了实际应用中的常见基础功能库，可辅助开发者进行复杂证明的组合实现。以在匿名数字货币<code>Zcash</code>中的应用为开端，<code>libsnark</code>奠定了零知识证明技术从理论研究到大规模工程应用的基础。</p>
<h3 id="bellman"><a href="#bellman" class="headerlink" title="bellman"></a>bellman</h3><p>在<code>Zcash</code>项目中，最初采用<code>libsnark</code>算法库实现<code>zk-SNARK</code>零知识证明。在<code>2018</code>年升级到<code>Sapling</code>版本时，由于之前采用的<code>libsnark</code>版本较老，其中关于椭圆曲线和<code>zk-SNARK</code>方案的选择都已不是当时的最优选项，<code>Zcash</code>改为使用自研的<code>bellman</code>算法库。<code>bellman</code>是<code>Zcash</code>团队基于<code>Rust</code>语言实现的<code>zk-SNARK</code>算法库，支持<code>Groth16</code>论文方案，目前主要在<code>Zcash</code>项目中应用。</p>
<h3 id="ZoKrates"><a href="#ZoKrates" class="headerlink" title="ZoKrates"></a>ZoKrates</h3><p><code>ZoKrates</code>是一个部分基于<code>libsnark</code>、部分采用<code>Rust</code>语言重写的<code>zk-SNARK</code>实现工具，默认支持<code>Groth16</code>方案，开发者需要使用一种自建的脚本语言进行代码编写，目前在实际工程中仅用于在以太坊智能合约上部署支持零知识证明的应用。</p>
<h2 id="零知识证明的优缺点"><a href="#零知识证明的优缺点" class="headerlink" title="零知识证明的优缺点"></a>零知识证明的优缺点</h2><p><strong>优点</strong></p>
<ul>
<li>在使用零知识证明时，不会降低安全性；</li>
<li>具有完整隐秘性；</li>
<li>安全性依赖于未解决的数学难题（如离散对数、大整数因子分解、平方根等等）；</li>
</ul>
<p><strong>缺点</strong></p>
<ul>
<li>生成零知识证明需要大量的算力</li>
<li>部分协议需要可信设置</li>
<li>部分协议不能抗量子计算</li>
</ul>

    </div>

    
    
    
      
  <div class="popular-posts-header">相关文章推荐</div>
  <ul class="popular-posts">
    <li class="popular-posts-item">
      <div class="popular-posts-title"><a href="/posts/318c223a.html" rel="bookmark">zkRollup介绍 原理篇 </a></div>
    </li>
    <li class="popular-posts-item">
      <div class="popular-posts-title"><a href="/posts/3e17fcd9.html" rel="bookmark">科普：什么是以太坊</a></div>
    </li>
    <li class="popular-posts-item">
      <div class="popular-posts-title"><a href="/posts/2e1e9deb.html" rel="bookmark">精通 Uniswap</a></div>
    </li>
    <li class="popular-posts-item">
      <div class="popular-posts-title"><a href="/posts/7664e5f1.html" rel="bookmark">暂停交易？ERC20合约整数溢出安全漏洞案例技术分析（一）</a></div>
    </li>
    <li class="popular-posts-item">
      <div class="popular-posts-title"><a href="/posts/c052872a.html" rel="bookmark">理解以太坊中智能合约中的存储</a></div>
    </li>
  </ul>


    <footer class="post-footer">
          

<div class="post-copyright">
<ul>
  <li class="post-copyright-author">
      <strong>原作者： </strong>吴寿鹤
  </li>
  <li class="post-copyright-link">
      <strong>本文链接：</strong>
      <a href="https://www.whatsblockchain.com/posts/58cf1c1b.html" title="零知识证明介绍 ">https://www.whatsblockchain.com/posts/58cf1c1b.html</a>
  </li>
  <li class="post-copyright-license">
    <strong>版权声明： </strong>本博客所有文章除特别声明外，均采用 <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/" rel="noopener" target="_blank"><i class="fab fa-fw fa-creative-commons"></i>BY-NC-SA</a> 许可协议。转载请注明出处！
  </li>
</ul>
</div>

          <div class="post-tags">
              <a href="/tags/%E4%BB%A5%E5%A4%AA%E5%9D%8A/" rel="tag"># 以太坊</a>
              <a href="/tags/%E9%9B%B6%E7%9F%A5%E8%AF%86%E8%AF%81%E6%98%8E/" rel="tag"># 零知识证明</a>
              <a href="/tags/%E5%8C%BA%E5%9D%97%E9%93%BE/" rel="tag"># 区块链</a>
          </div>

        

          <div class="post-nav">
            <div class="post-nav-item">
                <a href="/posts/318c223a.html" rel="prev" title="zkRollup介绍 原理篇 ">
                  <i class="fa fa-chevron-left"></i> zkRollup介绍 原理篇 
                </a>
            </div>
            <div class="post-nav-item">
                <a href="/posts/2e1e9deb.html" rel="next" title="精通 Uniswap">
                  精通 Uniswap <i class="fa fa-chevron-right"></i>
                </a>
            </div>
          </div>
    </footer>
  </article>
  
  
  



      

<script>
  window.addEventListener('tabs:register', () => {
    let { activeClass } = CONFIG.comments;
    if (CONFIG.comments.storage) {
      activeClass = localStorage.getItem('comments_active') || activeClass;
    }
    if (activeClass) {
      const activeTab = document.querySelector(`a[href="#comment-${activeClass}"]`);
      if (activeTab) {
        activeTab.click();
      }
    }
  });
  if (CONFIG.comments.storage) {
    window.addEventListener('tabs:click', event => {
      if (!event.target.matches('.tabs-comment .tab-content .tab-pane')) return;
      const commentClass = event.target.classList[1];
      localStorage.setItem('comments_active', commentClass);
    });
  }
</script>

    </div>
  </main>

  <footer class="footer">
    <div class="footer-inner">
      

      

<div class="copyright">
  
  &copy; 
  <span itemprop="copyrightYear">2020</span>
  <span class="with-love">
    <i class="fa fa-heart"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">吴寿鹤</span>
</div>
<div class="wordcount">
  <span class="post-meta-item">
    <span class="post-meta-item-icon">
      <i class="fa fa-chart-line"></i>
    </span>
      <span>站点总字数：</span>
    <span title="站点总字数">87k</span>
  </span>
  <span class="post-meta-item">
    <span class="post-meta-item-icon">
      <i class="fa fa-coffee"></i>
    </span>
      <span>站点阅读时长 &asymp;</span>
    <span title="站点阅读时长">1:19</span>
  </span>
</div>
<div class="busuanzi-count">
    <span class="post-meta-item" id="busuanzi_container_site_uv" style="display: none;">
      <span class="post-meta-item-icon">
        <i class="fa fa-user"></i>
      </span>
      <span class="site-uv" title="总访客量">
        <span id="busuanzi_value_site_uv"></span>
      </span>
    </span>
    <span class="post-meta-item" id="busuanzi_container_site_pv" style="display: none;">
      <span class="post-meta-item-icon">
        <i class="fa fa-eye"></i>
      </span>
      <span class="site-pv" title="总访问量">
        <span id="busuanzi_value_site_pv"></span>
      </span>
    </span>
</div>
  <div class="powered-by">由 <a href="https://hexo.io/" class="theme-link" rel="noopener" target="_blank">Hexo</a> & <a href="https://theme-next.js.org/" class="theme-link" rel="noopener" target="_blank">NexT.Gemini</a> 强力驱动
  </div>

    </div>
  </footer>

  
  <script src="//cdn.jsdelivr.net/npm/animejs@3.2.0/lib/anime.min.js"></script>
<script src="/js/utils.js"></script><script src="/js/motion.js"></script><script src="/js/next-boot.js"></script>

  
  <script>
    (function(){
      var bp = document.createElement('script');
      var curProtocol = window.location.protocol.split(':')[0];
      bp.src = (curProtocol === 'https') ? 'https://zz.bdstatic.com/linksubmit/push.js' : 'http://push.zhanzhang.baidu.com/push.js';
      var s = document.getElementsByTagName("script")[0];
      s.parentNode.insertBefore(bp, s);
    })();
  </script>


















  
  <script async src="https://busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>








  

  
      <script>
  if (typeof MathJax === 'undefined') {
    window.MathJax = {
      tex: {
        inlineMath: {'[+]': [['$', '$']]},
        tags: 'ams'
      },
      options: {
        renderActions: {
          findScript: [10, doc => {
            document.querySelectorAll('script[type^="math/tex"]').forEach(node => {
              const display = !!node.type.match(/; *mode=display/);
              const math = new doc.options.MathItem(node.textContent, doc.inputJax[0], display);
              const text = document.createTextNode('');
              node.parentNode.replaceChild(text, node);
              math.start = {node: text, delim: '', n: 0};
              math.end = {node: text, delim: '', n: 0};
              doc.math.push(math);
            });
          }, '', false],
          insertedScript: [200, () => {
            document.querySelectorAll('mjx-container').forEach(node => {
              const target = node.parentNode;
              if (target.nodeName.toLowerCase() === 'li') {
                target.parentNode.classList.add('has-jax');
              }
            });
          }, '', false]
        }
      }
    };
    const script = document.createElement('script');
    script.src = '//cdn.jsdelivr.net/npm/mathjax@3.1.0/es5/tex-mml-chtml.js';
    script.defer = true;
    document.head.appendChild(script);
  } else {
    MathJax.startup.document.state(0);
    MathJax.typesetClear();
    MathJax.texReset();
    MathJax.typeset();
  }
</script>

    

  

</body>
</html>
